package com.jishuo.nontax.bfc.ca;

import cn.com.jit.assp.dsign.DSign;
import com.jishuo.base.config.NonTaxConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ResourceBundle;

/**
 * 报文签名加密，isencrpt：1-吉大CA，2-软证书；3-Base64
 * 吉大签名、加密
 */
@Slf4j
@Component
public class JDCA {
    @Resource
    private NonTaxConfig nonTaxConfig;

    /** 初始化 */
    public DSign init() {
        DSign dSign = new DSign();
        DSign.init("/ca.properties");
        return dSign;
    }

    /**
     * 签名
     * @param oriData 原始数据
     * @param certID 证书ID
     * @param isencrpt 加密方式
     * @return
     */
    public String signMessage(String oriData, String certID, String isencrpt) {
        try {
            // 获取指定字符集的字节流
            byte[] oriDataBytes = oriData.getBytes(nonTaxConfig.TLQ_Charset_CZ);
            if ("1".equals(isencrpt)) {
                String signData = null; // 返回签名结果
                DSign dSign = init();
                signData = dSign.detachSign(certID, oriDataBytes);
                if (signData == null || signData.length() == 0){
                    log.info("吉大CA签名失败！Code={}，msg={}", dSign.getErrorCode(), dSign.getErrorMessage());
                }
                return signData;
            } else if ("2".equals(isencrpt)){
                return this.encodeData(oriDataBytes, certID);
            } else {
                return Base64.encodeBase64String(oriDataBytes);
            }
        } catch (Exception ex) {
            log.info("签名失败!", ex);
            return null;
        }
    }

    /**
     * 签名验证
     * @param signData 签名数据
     * @param oriData 原始数据
     * @param isencrpt 加密方式
     * @return
     */
    public boolean verifySignMessage(String signData, String oriData, String isencrpt) {
        try {
            // 获取指定字符集的字节流
            byte[] oriDataBytes = oriData.getBytes(nonTaxConfig.TLQ_Charset_CZ);
            if ("1".equals(isencrpt)){
                DSign dSign = init();
                if (dSign.verifyDetachedSign(signData.getBytes(),oriDataBytes) == 0) {
                    return true;
                } else {
                    log.info("吉大CA验签失败！Code={}，msg={}", dSign.getErrorCode(), dSign.getErrorMessage());
                    return false;
                }
            } else if ("2".equals(isencrpt)) {
                String tmp = new String(this.decodeData(signData), nonTaxConfig.TLQ_Charset_CZ);
                if (oriData.equals(tmp)) {
                    return true;
                }else{
                    log.info("验签失败！isencrpt={}", isencrpt);
                    return false;
                }
            }else{
                return true;
            }
        } catch (Exception ex) {
            log.info("验签错误!", ex);
            return false;
        }
    }

    /**
     * 加密
     * @param oriData 原始数据
     * @param certID CA证书ID
     * @param isencrpt 加密方式
     * @return
     */
    public String encodeEnvelop(String oriData, String certID, String isencrpt) {
        try {
            // 获取指定字符集的字节流
            byte[] oriDataBytes = oriData.getBytes(nonTaxConfig.TLQ_Charset_CZ);
            if ("1".equals(isencrpt)) {
                String envelopData = null; // 返回加密结果
                DSign dSign = init();
                String[] DE_CERT_ID = new String[] {certID};
                envelopData = dSign.encryptEnvelop(DE_CERT_ID, oriDataBytes);
                if (envelopData == null || envelopData.length() == 0) {
                    log.info("吉大CA加密报文失败！Code={}，msg={}", dSign.getErrorCode(), dSign.getErrorMessage());
                }
                return envelopData;
            } else if ("2".equals(isencrpt)) {
                return this.encodeData(oriDataBytes, certID);
            } else {
                return Base64.encodeBase64String(oriDataBytes);
            }
        } catch (Exception ex) {
            log.info("加密报文错误。", ex);
            return null;
        }
    }

    /**
     * 解密
     * @param envelopData 密文
     * @param isencrpt 加密方式
     * @return
     */
    public String decodeEnvelop(String envelopData, String isencrpt) {
        String oriData = null;
        try {
            byte[] envelopDataBytes = envelopData.getBytes();
            if ("1".equals(isencrpt)) {
                // 旧版本sdk，无法更改字符集，重写类
//                JitDSign dSign = new JitDSign();
//                JitDSign.init("/ca.properties");
                // 新版本sdk
                DSign dSign = init();
                if (dSign.decryptEnvelop(envelopDataBytes) == 0) {
                    oriData = new String(dSign.getPlainByteData(), nonTaxConfig.TLQ_Charset_CZ);
                    if (oriData.length() == 0) log.info("吉大CA解密成功，但是报文为空。");
                    return oriData;
                } else {
                    log.info("吉大CA解密报文失败！Code={}，msg={}", dSign.getErrorCode(), dSign.getErrorMessage());
                    return null;
                }
            } else if ("2".equals(isencrpt)) {
                return new String(this.decodeData(envelopData), nonTaxConfig.TLQ_Charset_CZ);
            } else {
                return new String(Base64.decodeBase64(envelopData), nonTaxConfig.TLQ_Charset_CZ);
            }
        } catch (Exception ex) {
            log.info("解密报文错误。", ex);
            return null;
        }
    }

    /**
     * 软证书加密
     * @param oriDataBytes 原始字节流
     * @param key 公钥
     * @return
     */
    public String encodeData(byte[] oriDataBytes, String key) {
        try {
            PublicKey pubkey = RsaHelper.decodePublicKeyFromXml(key);
            byte[] encryptedDataByteArray = RsaHelper.encryptData(oriDataBytes, pubkey);
            return Base64.encodeBase64String(encryptedDataByteArray);
        } catch (Exception ex) {
            log.info("证书加密错误。", ex);
            return null;
        }
    }

    /**
     * 证书解密
     * @param envelopData 密文
     * @return
     */
    public byte[] decodeData(String envelopData){
        try{
            String key = ResourceBundle.getBundle("init").getString("prikey");
            PrivateKey prikey = RsaHelper.decodePrivateKeyFromXml(key);
            byte[] dataByteArray = Base64.decodeBase64(envelopData);
            byte[] encryptedDataByteArray = RsaHelper.decryptData(dataByteArray, prikey);
            return encryptedDataByteArray;
        } catch(Exception ex){
            log.info("证书解密错误。", ex);
            return null;
        }
    }
}
